package com.bolt.report.engine.query;

import com.bolt.common.BoltConstants;
import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.collection.MapUtil;
import com.bolt.common.reflect.ClassUtil;
import com.bolt.common.utils.ApacheRequestUtil;
import com.bolt.common.utils.JacksonUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.convention.exception.ServiceException;
import com.bolt.report.config.ReportTokenService;
import com.bolt.report.definition.DataSetDefinition;
import com.bolt.report.definition.ParameterDefinition;
import com.bolt.report.definition.RequestType;
import com.bolt.report.engine.ApiDataConvertAdapter;
import com.bolt.report.engine.BRDataSource;
import com.bolt.report.engine.CollectionDataSource;
import com.bolt.report.engine.ObjectFactory;
import com.bolt.report.exception.ReportBizExceptionEnum;
import com.bolt.report.exception.ReportException;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ApiHttpQueryExecute implements QueryExecute {

    private final Log logger = LogFactory.getLog(ApiHttpQueryExecute.class);


    private DataSetDefinition dataSetDefinition;

    private Map<String, Object> parameters;

    private Header tokenHeader;


    public ApiHttpQueryExecute(DataSetDefinition dataSetDefinition, Map<String, Object> parameters) {
        this.dataSetDefinition = dataSetDefinition;
        if (MapUtil.isNotEmpty(parameters)) {
            setParameters(parameters);
        }
        setTokenHeader(parameters);
    }

    private void setParameters(Map<String, Object> param) {
        if (IteratorUtil.isEmpty(dataSetDefinition.getParameters())) {
            this.parameters = Collections.emptyMap();
        } else {
            this.parameters = new HashMap<>();
            for (ParameterDefinition parameterDef : dataSetDefinition.getParameters()) {
                if (!param.containsKey(parameterDef.getName())) {
                    param.put(parameterDef.getName(), parameterDef.getDefaultValue());
                } else {
                    parameters.put(parameterDef.getName(), param.get(parameterDef.getName()));
                }
            }

        }
    }

    private void setTokenHeader(Map<String, Object> param) {
        ReportTokenService tokenService = ObjectFactory.getTokenService();
        String token = tokenService.getToken();
        if (StrUtil.isNotBlank(token)) {
            tokenHeader = new BasicHeader(BoltConstants.AUTH_HEADER, token);
        } else if (MapUtil.isNotEmpty(param) && param.containsKey("token")) {
            tokenHeader = new BasicHeader(BoltConstants.AUTH_HEADER, (String) param.get("token"));
        } else {
            tokenHeader = null;
        }
    }

    @Override
    public BRDataSource createBRDataSource() {
        try {
            if (StrUtil.isEmpty(dataSetDefinition.getApiUrl())) {
                throw new ServiceException(ReportBizExceptionEnum.API_URL_EMPRY);
            }
            String context = null;
            switch (dataSetDefinition.getApiMethod()) {
                case GET:
                    context = ApacheRequestUtil.get(dataSetDefinition.getApiUrl(), tokenHeader, parameters);
                    break;
                case POST:
                    if (dataSetDefinition.getApiRequestType() == RequestType.FORMDATA) {
                        context = ApacheRequestUtil.post(dataSetDefinition.getApiUrl(), tokenHeader, parameters);
                    } else {
                        context = ApacheRequestUtil.post(dataSetDefinition.getApiUrl(), tokenHeader, JacksonUtil.toJSONString(parameters));
                    }
                    break;
                default:
                    context = ApacheRequestUtil.get(dataSetDefinition.getApiUrl(), tokenHeader, parameters);
            }
            if (StrUtil.isEmpty(context)) {
                logger.error(ReportBizExceptionEnum.RESPONSE_CONTENT_EMPTY);
                return new CollectionDataSource(Collections.emptyList());
            }

            JsonNode jsonObject = JacksonUtil.getObjectMapper().readTree(context);
            if (!jsonObject.has("data") && StrUtil.isEmpty(dataSetDefinition.getApiConvert())) {
                throw new ServiceException(ReportBizExceptionEnum.RESPONSE_JSON_FORMART_ERROR);
            }
            if (!jsonObject.has("data") && StrUtil.isNotEmpty(dataSetDefinition.getApiConvert())) {
                Object convertAdapter = ClassUtil.newInstance(dataSetDefinition.getApiConvert());
                if (convertAdapter instanceof ApiDataConvertAdapter) {
                    String newContext = ((ApiDataConvertAdapter) convertAdapter).convert(context);
                    jsonObject = JacksonUtil.getObjectMapper().readTree(newContext);
                }
            }
            List<Map> data = JacksonUtil.toList(jsonObject.get("data").toString(), Map.class);
            return new CollectionDataSource(data);
        } catch (Exception ex) {
            throw new ReportException(ex);
        }

    }

    @Override
    public List<?> queryData() {
        return ((CollectionDataSource) createBRDataSource()).getData();
    }
}